package com.magnificent.atlantis.client.data.task;

import com.magnificent.atlantis.client.MainLoad;
import com.magnificent.atlantis.client.data.message.ClientMessageHelper;
import com.magnificent.atlantis.client.data.message.MessageType;
import com.magnificent.atlantis.client.data.message.messages.ClientInviteMessage;
import com.magnificent.atlantis.client.data.message.messages.ClientMessage;
import com.magnificent.atlantis.client.data.message.messages.ClientNewMeetingMessage;
import com.magnificent.atlantis.client.data.message.messages.ClientUpdateMeetingMessage;
import com.magnificent.atlantis.client.data.task.creator.AbstractCreatorTask;
import com.magnificent.atlantis.client.data.task.planner.AbstractPlannerTask;
import com.magnificent.atlantis.client.data.task.planner.CommunityMeetingPlannerTask;
import com.magnificent.atlantis.client.event.EventDispatcher;
import com.magnificent.atlantis.client.event.EventType;
import com.magnificent.atlantis.client.ui.creator.tasktreetable.data.CreatorTableNode;
import com.magnificent.atlantis.client.ui.planner.dialogs.task.PlannerTaskDialog;
import com.magnificent.atlantis.client.ui.planner.panels.task.treetable.data.PlannerTableNode;

import java.util.*;

/**
 * User: Babanin
 * Date: 05.05.2009
 * Time: 17:26:45
 */
public final class TaskHelper {
    public static java.util.List<AbstractPlannerTask> tasksById(java.util.List<Integer> dependencyTasks, java.util.List<AbstractPlannerTask> taskList) {
        java.util.List<AbstractPlannerTask> result = new ArrayList<AbstractPlannerTask>(dependencyTasks.size());

        for (Integer id : dependencyTasks) {
            for (AbstractPlannerTask abstractTask : taskList) {
                if (abstractTask.getId() == id) {
                    result.add(abstractTask);
                    break;
                }
            }
        }

        return result;
    }

    public static List<Integer> getListOfTaskIds(PlannerTaskDialog.PlannerDependencyTableModel taskTableModel) {
        List<Integer> result = new ArrayList<Integer>();
        List<AbstractPlannerTask> plannerTasks = taskTableModel.getTasks();

        for (AbstractPlannerTask abstractPlannerTask : plannerTasks) {
            result.add(abstractPlannerTask.getId());
        }

        return result;
    }

    public static PlannerTableNode buildFullTree(List<AbstractPlannerTask> abstractPlannerTaskList, TaskFilter taskFilter) {
        PlannerTableNode root = new PlannerTableNode(null, null);

        Collections.sort(abstractPlannerTaskList);
        updateIndexes(abstractPlannerTaskList);

        for (AbstractPlannerTask subPlannerTask : abstractPlannerTaskList) {
            if(!taskFilter.isOk(subPlannerTask)){
                continue;
            }

            root.getChildren().add(buildSubTree(subPlannerTask, root, taskFilter));
        }

        return root;
    }

    public static boolean skip(AbstractPlannerTask subPlannerTask, boolean showActive, boolean showFinished) {
        if (showActive && showFinished) {
            return false;
        }

        if (subPlannerTask.isBasicTask()) {
            if (subPlannerTask.getBasicTask().getProgress() == 100) {
                return !showFinished;
            } else {
                return !showActive;
            }
        } else {
            if (subPlannerTask.getMeetingTask().isCompleted()) {
                return !showFinished;
            } else {
                return !showActive;
            }
        }
    }

    public static PlannerTableNode buildSubTree(AbstractPlannerTask plannerTask, PlannerTableNode parent, TaskFilter taskFilter) {
        PlannerTableNode creatorTableNode = new PlannerTableNode(plannerTask, parent);

        if (plannerTask.isBasicTask()) {
            Collections.sort(plannerTask.getBasicTask().getSubTasks());
            updateIndexes(plannerTask.getBasicTask().getSubTasks());

            for (AbstractPlannerTask subPlannerTask : plannerTask.getBasicTask().getSubTasks()) {
                if (!taskFilter.isOk(subPlannerTask)) {
                    continue;
                }

                creatorTableNode.getChildren().add(buildSubTree(subPlannerTask, creatorTableNode, taskFilter));
            }
        }

        return creatorTableNode;
    }

    public static CreatorTableNode buildFullTree(List<AbstractCreatorTask> abstractTaskList) {
        CreatorTableNode root = new CreatorTableNode(null, null);

        for (AbstractCreatorTask subTask : abstractTaskList) {
            root.getChildren().add(buildSubTree(subTask, root));
        }

        return root;
    }

    public static CreatorTableNode buildSubTree(AbstractCreatorTask task, CreatorTableNode parent) {
        CreatorTableNode creatorTableNode = new CreatorTableNode(task, parent);

        if (task.isBasicTask()) {
            for (AbstractCreatorTask subTask : task.getBasicTask().getSubTasks()) {
                creatorTableNode.getChildren().add(buildSubTree(subTask, creatorTableNode));
            }
        }

        return creatorTableNode;
    }

    public static void updateIndexes(List<AbstractPlannerTask> plannerTaskList) {
        int[] newIndexes = new int[plannerTaskList.size() + 10];
        Arrays.fill(newIndexes, -1);

        int id = 1;
        for (AbstractPlannerTask plannerTask : plannerTaskList) {
            newIndexes[plannerTask.getId()] = id;
            plannerTask.setId(id++);

            if (plannerTask.getDependencyTaskId() != -1) {
                plannerTask.setDependencyTaskId(newIndexes[plannerTask.getDependencyTaskId()]);
            }

            final List<Integer> dependencyTasks = plannerTask.getDependencyTasks();
            if (dependencyTasks.size() != 0) {
                List<Integer> newDependencyTasks = new ArrayList<Integer>();

                for (Integer i : dependencyTasks) {
                    if (newIndexes[i] != -1) {
                        newDependencyTasks.add(newIndexes[i]);
                    }
                }

                plannerTask.setDependencyTasks(newDependencyTasks);
            }
        }
    }

    public static void deleteTask(AbstractPlannerTask plannerTask, List<AbstractPlannerTask> plannerTaskList) {
        int id = plannerTask.getId();
        plannerTaskList.remove(plannerTask);

        for (AbstractPlannerTask abstractPlannerTask : plannerTaskList) {
            if (abstractPlannerTask.getDependencyTaskId() == id) {
                abstractPlannerTask.setDependencyTaskId(-1);
                abstractPlannerTask.setDependencyTaskTime(0);
            }

            abstractPlannerTask.getDependencyTasks().remove((Object) id);
        }
    }

    public static void updateTime(AbstractPlannerTask plannerTask, List<AbstractPlannerTask> plannerTaskList, Date startDate) {
        if (plannerTask == null) {
            return;
        }

        int id = plannerTask.getId();
        plannerTask.reInitializeStartDate(startDate);

        for (AbstractPlannerTask abstractPlannerTask : plannerTaskList) {
            if (abstractPlannerTask.getDependencyTaskId() == id) {
                updateTime(abstractPlannerTask, plannerTaskList, new Date(startDate.getTime() + abstractPlannerTask.getDependencyTaskTime()));
            }
        }
    }

    public static void taskUpdated(CommunityMeetingPlannerTask task, String oldTitle, boolean reInvite) {
        List<ClientMessage> outbox = MainLoad.getPlannerData().getMessagesContainer().getMessages(MessageType.OUTBOX);

        if (task.getMeetingId() == -1) {
            for (ClientMessage clientMessage : outbox) {
                if (clientMessage instanceof ClientNewMeetingMessage) {
                    ClientNewMeetingMessage meetingMessage = (ClientNewMeetingMessage) clientMessage;
                    if (meetingMessage.getLocalTaskId() == task.getId()) {
                        meetingMessage.setDate(task.getStartDate());
                        meetingMessage.setMeetingTitle(task.getName());
                        meetingMessage.setMessage(task.getDescription());
                        meetingMessage.setUsersToIds(task.getInvitedUsers());
                        meetingMessage.setInvitedUsers((ArrayList<Integer>) task.getInvitedUsers());

                        EventDispatcher.getInstance().postEvent(EventType.MESSAGE_UPDATED, meetingMessage);
                    }
                }
            }
        } else {
            boolean found = false;

            for (ClientMessage clientMessage : outbox) {
                if (clientMessage instanceof ClientUpdateMeetingMessage) {
                    ClientUpdateMeetingMessage meetingMessage = (ClientUpdateMeetingMessage) clientMessage;
                    if (meetingMessage.getLocalTaskId() == task.getId()) {
                        found = true;

                        meetingMessage.setLocalTaskId(task.getId());
                        meetingMessage.setOldTitle(oldTitle);
                        meetingMessage.setDate(task.getStartDate());
                        meetingMessage.setMeetingTitle(task.getName());
                        meetingMessage.setComment(task.getDescription());
                        meetingMessage.setMeetingId(task.getMeetingId());
                        meetingMessage.setMessageType(MessageType.OUTBOX);
                        meetingMessage.setInvitedUsers((ArrayList<Integer>) task.getInvitedUsers());
                        meetingMessage.setUsersToIds(task.getInvitedUsers());
                        meetingMessage.setSentDate(new Date());
                        meetingMessage.setReInvite(reInvite);

                        EventDispatcher.getInstance().postEvent(EventType.MESSAGE_UPDATED, meetingMessage);
                        break;
                    }
                }
            }

            if (!found) {
                ClientUpdateMeetingMessage message = ClientMessageHelper.createUpdateMeetingMessage(task, oldTitle, reInvite);

                MainLoad.getPlannerData().getMessagesContainer().addMessage(message);
                EventDispatcher.getInstance().postEvent(EventType.NEW_MESSAGE, message);
            }
        }
    }

    public static void updateMeetingId(int meetingId, int taskId) {
        List<AbstractPlannerTask> tasks = MainLoad.getPlannerData().getConfigurationContainer().getDataTasks();
        for (AbstractPlannerTask plannerTask : tasks) {
            if ((plannerTask instanceof CommunityMeetingPlannerTask) && (plannerTask.getId() == taskId)) {
                ((CommunityMeetingPlannerTask) plannerTask).setMeetingId(meetingId);
            }
        }
    }

    public static <T> List<T> getAllTasks(Class<T> taskClass) {
        List<T> result = new ArrayList<T>();
        List<AbstractPlannerTask> abstractPlannerTasks = MainLoad.getPlannerData().getConfigurationContainer().getDataTasks();

        for (AbstractPlannerTask abstractPlannerTask : abstractPlannerTasks) {
            if (abstractPlannerTask.getClass().equals(taskClass)) {
                result.add((T) abstractPlannerTask);
            }
        }

        return result;
    }

    public static List<Integer> getAllTasksIds(Class taskClass) {
        List<Integer> result = new ArrayList<Integer>();
        List<AbstractPlannerTask> abstractPlannerTasks = MainLoad.getPlannerData().getConfigurationContainer().getDataTasks();

        for (AbstractPlannerTask abstractPlannerTask : abstractPlannerTasks) {
            if (abstractPlannerTask.getClass().equals(taskClass)) {
                result.add(abstractPlannerTask.getId());
            }
        }

        return result;
    }

    public static List<Integer> getAllMeetingIds() {
        List<Integer> result = new ArrayList<Integer>();
        List<AbstractPlannerTask> abstractPlannerTasks = MainLoad.getPlannerData().getConfigurationContainer().getDataTasks();

        for (AbstractPlannerTask abstractPlannerTask : abstractPlannerTasks) {
            if (abstractPlannerTask.getClass().equals(CommunityMeetingPlannerTask.class)) {
                result.add(((CommunityMeetingPlannerTask) abstractPlannerTask).getMeetingId());
            }
        }

        return result;
    }

    public static void merge(CommunityMeetingPlannerTask task, ClientInviteMessage message) {
        task.setOwner(false);
        task.setMeetingId(message.getMeetingId());
        task.setInvitedUsers(message.getInvitedUsers());

        task.setStartDate(message.getDate());
        task.setName(message.getMeetingTitle());
        task.setDescription(message.getComment());
        task.setConfigurationId(message.getConfigurationId());
    }
}
